parser grammar cLPMEDIntelliSenseParser;

options
{
	output = AST;
	ASTLabelType=CommonTree;
	language = CSharp2;
	tokenVocab = LPMEDLexer;
}

@header
{
	using System.Collections.Generic;
	using System.Linq;
}

@members
{
	public List<Exception> Logger = new List<Exception>();
	
	private int cursorLocationX = -1;
	private int cursorLocationY = -1;
	public string ContextType = "Clear";
	public List<IToken> Domain = new List<IToken>();

	private void SetContext(string context, IToken main, IList children, IToken last)
    {
        if ((main.CharPositionInLine < cursorLocationX) && (main.Line <= cursorLocationY))
        {
            ContextType = context;
            Domain.Clear();
            Domain.Add(main);
          
            var domainsToAdd = new List<IToken>();
            if (children != null)
                domainsToAdd.AddRange(children.Cast<IToken>());
            if (last != null)        
                domainsToAdd.Add(last);
          
            Domain.AddRange(from domain in domainsToAdd
                           where (domain.Line < cursorLocationY)
                                || ((domain.Line == cursorLocationY) && ((domain.CharPositionInLine < cursorLocationX)))
                           select domain);
        }
    }
    private void ResetContext(IToken anyToken)
    {
        if ((anyToken.CharPositionInLine < cursorLocationX) && (anyToken.Line <= cursorLocationY))
        {
            ContextType = "Clear";
            Domain.Clear();
        }
    }
}

@namespace { Core.ANTLRGrammars }

program[int cursorLocationX, int cursorLocationY]
options
{
  backtrack = false;
}
@init
{
	this.cursorLocationX = cursorLocationX;
	this.cursorLocationY = cursorLocationY;
}
:
  atom+
;

atom
options
{
  backtrack = false;
}
:
        newID
    |   allChildren
    |   trash
;

newID
options
{
    backtrack = true;
}
:
    main = ID (DOT children += ID)* 
        {
            var currentToken = this.TokenStream.Get((($children != null) && ($children.Count > 0)) ? 
                ($children[$children.Count - 1] as IToken).TokenIndex
                : $main.TokenIndex);
            if (currentToken.TokenIndex < this.TokenStream.Size() - 1)
            {
                var nextToken = this.TokenStream.Get(currentToken.TokenIndex + 1);
                
                switch (nextToken.Type)
                {
                    case 67: //if after current goes WhiteSpace
                        ResetContext(currentToken);
                        break;
                    case 76: //if after current goes DOT
                        SetContext("AllChildren", $main, $children, null);
                        break;
                    default: //else it's continuing of current dotted name
                        SetContext("NewID", $main, $children, null);
                        break;
                }
            }
            else
                SetContext("NewID", $main, $children, null);
        }
;

allChildren
options
{
    backtrack = true;
}
:
    (children += ID DOT)+
        {
            var idfirstName = $children[0] as IToken;
            $children.Remove(idfirstName);
            SetContext("AllChildren", idfirstName, $children, null);
        }
;

trash
options
{
    backtrack = true;
}
:
        TERMINATEALL {ResetContext($TERMINATEALL);}
    |   OpIncDec {ResetContext($OpIncDec);}
    |   OpNegation {ResetContext($OpNegation);}
    |   OpUnar {ResetContext($OpUnar);}
    |   OpDivMul {ResetContext($OpDivMul);}
    |   OpAddSub {ResetContext($OpAddSub);}
    |   OpLogicalA {ResetContext($OpLogicalA);}
    |   OpLogicalB {ResetContext($OpLogicalB);}
    |   OpAnd {ResetContext($OpAnd);}
    |   OpOr {ResetContext($OpOr);}
    |   INT {ResetContext($INT);}
    |   FLOAT {ResetContext($FLOAT);}
    |   WS {ResetContext($WS);}
    |   LINECOMMENT {ResetContext($LINECOMMENT);}
    |   OBRACKET {ResetContext($OBRACKET);}
    |   CBRACKET {ResetContext($CBRACKET);}
    |   CURLYOBRACKET {ResetContext($CURLYOBRACKET);}
    |   CURLYCBRACKET {ResetContext($CURLYCBRACKET);}
    |   EQUALS {ResetContext($EQUALS);}
    |   first = EQUALS EQUALS {ResetContext($first);}  
    |   SEMI {ResetContext($SEMI);}
    |   COLON {ResetContext($COLON);}
    |   COMMA {ResetContext($COMMA);}
    |   dot = DOT (DOT)+ {ResetContext($dot);}
;